﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Firefly.Data {
    public static class WorldFile {

        public static void CheckIntegrity() {
            if(!Directory.Exists(mWorldFileLocation)) {
                try {
                    Directory.CreateDirectory(mWorldFileLocation);
                } catch (Exception e) {
                    throw new Exception(e.Message);
                }
            }
        }

        public static WorldConfig Load(string world) {
            Console.WriteLine("Attempting to load: " + world + " (" + world.Length + ")");
            using (FileStream fs = File.OpenRead(mWorldFileLocation + Base36.Decode(world) + ".dat")) {
                byte[] bytes = new byte[new FileInfo(mWorldFileLocation + Base36.Decode(world) + ".dat").Length];
                fs.Read(bytes, 0, bytes.Length);

                WorldConfig wc = new WorldConfig();
                Character tc = null;
                int index = 0;
                while (index < bytes.Length) {
                    List<byte> byteLine = new List<byte>();
                    while (true) {
                        if ((char)bytes[index] != '\n') {
                            byteLine.Add(bytes[index]);
                            index++;
                        } else {
                            string[] sa = DecodeLine(byteLine.ToArray());
                            Console.WriteLine("Decoded: " + sa[1]);
                            switch (sa[0]) {
                                case "World Name":
                                    Console.WriteLine("Loading world: " + sa[1]);
                                    wc.WorldName = sa[1];
                                    break;
                                case "ServerAddress":
                                    wc.ServerAddress = sa[1];
                                    break;
                                case "ServerPort":
                                    wc.ServerPort = Convert.ToInt32(sa[1]);
                                    break;
                                case "IFontFamily":
                                    //wc.InputFont = new System.Drawing.Font(sa[1], wc.InputFont.SizeInPoints);
                                    break;
                                case "IFontSize":
                                    //wc.InputFont = new System.Drawing.Font(wc.InputFont.FontFamily, (float)Convert.ToDouble(sa[1]));
                                    break;
                                case "OFontFamily":
                                    //wc.OutputFont = new System.Drawing.Font(sa[1], wc.OutputFont.SizeInPoints);
                                    break;
                                case "OFontSize":
                                    //wc.OutputFont = new System.Drawing.Font(wc.OutputFont.FontFamily, (float)Convert.ToDouble(sa[1]));
                                    break;
                                case "Character Name":
                                    if (tc != null)
                                        wc.Characters.Add(tc);
                                    tc = new Character();
                                    tc.Name = sa[1];
                                    break;
                                case "Password":
                                    tc.Password = sa[1];
                                    break;
                                case "IsDefault":
                                    tc.IsDefault = (sa[1] == "true") ? true : false;
                                    break;
                                case "AutoConnect":
                                    tc.AutoConnect = (sa[1] == "true") ? true : false;
                                    break;
                                default:
                                    break;
                            }
                            byteLine = new List<byte>();
                            index++;
                            break;
                        }
                    }
                }
                if(tc != null)
                    wc.Characters.Add(tc);

                return wc;
            }
        }

        public static void Save(WorldConfig wc) {
            CheckIntegrity();

            Console.WriteLine("Creating file.");
            using (FileStream fs = File.Create(mWorldFileLocation + Base36.Decode(wc.WorldName) + mWorldFileName)) {
                fs.WriteByte((byte)mWorldEscapeCode);
                AddText(fs, wc.WorldName);
                AddText(fs, "ServerAddress=" + wc.ServerAddress);
                AddText(fs, "ServerPort=" + wc.ServerPort);
                if(wc.BackupAddress != "")
                    AddText(fs, "BackupAddress=" + wc.BackupAddress);
                if(wc.BackupPort != 0)
                    AddText(fs, "BackupPort=" + wc.BackupPort);
                if (wc.ProxyAddress != "")
                    AddText(fs, "ProxyAddress=" + wc.ProxyAddress);
                if (wc.ProxyPort != 0)
                    AddText(fs, "ProxyPort=" + wc.ProxyPort);
                AddText(fs, "UsingProxy=" + wc.UsingProxy);
                AddText(fs, "IFontFamily=" + wc.InputFont.FontFamily);
                AddText(fs, "IFontSize=" + wc.InputFont.SizeInPoints);
                AddText(fs, "OFontFamily=" + wc.OutputFont.FontFamily);
                AddText(fs, "OFontSize=" + wc.OutputFont.SizeInPoints);
                // Character Data Tiems
                foreach (Character c in wc.Characters) {
                    Console.WriteLine("Writing Character: " + c.Name);
                    fs.Write(new byte[] {(byte)mCharEscapeCode}, 0, 1); // Char escape code is important.
                    AddText(fs, c.Name);
                    AddText(fs, "Password=" + c.Password);
                    AddText(fs, "IsDefault=" + c.IsDefault.ToString());
                    AddText(fs, "AutoConnect=" + c.AutoConnect.ToString());
                }
            }
        }

        public static string[] GetWorldList() {
            CheckIntegrity();

            List<string> worldNames = new List<string>();
            // Check each file in the worlds directory.
            foreach (string fn in Directory.GetFiles(mWorldFileLocation)) {
                using (FileStream fs = File.OpenRead(fn)) { // Open the file.
                    string s = String.Empty;
                    while (true) {
                        char c = (char)fs.ReadByte();
                        if (c != '\n')
                            s += c;
                        else
                            break;
                    }
                    Console.WriteLine("Found data file string: " + s);
                    char[] ca = s.ToCharArray();
                    // We have the string, move forward.
                    Console.WriteLine("Looking for: " + (int)mWorldEscapeCode + " But found " + (int)ca[0]);
                    if(ca.Length != 0)
                        if (ca[0] == (char)mWorldEscapeCode) {// It's a world name
                            worldNames.Add(s.TrimStart(ca[0]));
                            Console.WriteLine("Return file name to list");
                        }
                        
                }
            }
            // Return names
            return worldNames.ToArray();
        }

        private static void AddText(FileStream fs, string value) {
            byte[] info = new UTF8Encoding(true).GetBytes(value + "\n");
            fs.Write(info, 0, info.Length);
        }

        private static string[] DecodeLine(byte[] ba) {
            string s = Encoding.UTF8.GetString(ba);
            string[] property = new string[2];
            if (ba.Length != 0) {
                Console.WriteLine("Decoder: " + ba[0]);
                if ((int)ba[0] == mWorldEscapeCode) { // It's a world name
                    property[0] = "World Name";
                    property[1] = Encoding.UTF8.GetString(ba, 1, ba.Length - 1);
                    return property;
                } else if ((int)ba[0] == mCharEscapeCode) { // It's a character name.
                    property[0] = "Character Name";
                    property[1] = Encoding.UTF8.GetString(ba, 1, ba.Length - 1);
                    return property;
                } else if (s.Contains("=")) { // It's a property
                    property[0] = s.Substring(0, s.IndexOf('='));
                    property[1] = s.Substring(s.IndexOf('=') + 1, s.Length - property[0].Length - 1);
                    return property;
                }
            }
            // Could not decode.
            return property;
        }

        public static void Delete(string p) {
            if (File.Exists(mWorldFileLocation + Base36.Decode(p) + mWorldFileName)) {
                File.Delete(mWorldFileLocation + Base36.Decode(p) + mWorldFileName);
            } else {
                // Couldn't find world. Search all files.
                foreach(string fn in Directory.GetFiles(mWorldFileLocation)) {
                    string foundWorld = String.Empty;
                    using (FileStream fs = File.OpenRead(fn)) { // Open the file.
                        string s = String.Empty;
                        while (true) {
                            char c = (char)fs.ReadByte();
                            if (c != '\n')
                                s += c;
                            else
                                break;
                        }
                        char[] ca = s.ToCharArray();
                        // We have the string, move forward.
                        if (ca.Length != 0)
                            if (ca[0] == (char)mWorldEscapeCode) {// It's a world name
                                foundWorld = fn;
                            }
                    }

                    if (foundWorld != String.Empty)
                        File.Delete(mWorldFileLocation + fn + mWorldFileName);
                }
            }
        }

        public static string mWorldFileLocation = "worlds\\";
        public static string mWorldFileName = ".dat";
        public static int mWorldEscapeCode = 0x9c;
        public static int mCharEscapeCode = 0x8c;
        public const string illegalCharacters = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
    }
}
